﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Collections;

namespace GameLibrary.Settlement
{
    /// <summary>
    /// Represent built building.
    /// </summary>
    [Serializable]
    public class Buildings
    {
        #region variables

        private Dictionary<BuildingType, uint> buildingList;

        #endregion

        #region constructor

        public Buildings(Buildings buildings)
        {
            this.buildingList = new Dictionary<BuildingType, uint>(buildings.buildingList);
        }

        public Buildings()
        {
            this.buildingList = new Dictionary<BuildingType, uint> 
            { 
                { SettlementHelper.Road, 1 } 
            };// road lv 1 is default for any settlement.
        }

        #endregion

        #region this

        public uint this[BuildingType key]
        {
            get
            {
                if (this.buildingList.ContainsKey(key))
                    return this.buildingList[key];
                else
                    return 0;
            }
            private set
            {
                if (this.buildingList.ContainsKey(key))
                    this.buildingList[key] = value;
                else
                    this.Add(key, value);
            }
        }

        #endregion

        #region increase decrease level

        public void IncreaseLevel(BuildingType building, uint increasedLevel = 1)
        {
            if (this.buildingList.ContainsKey(building) == true)
                this.buildingList[building] += increasedLevel;
            else
            {
                this.buildingList.Add(building, increasedLevel);
            }
        }

        /// <summary>
        /// Try to decrease level decrease amount.
        /// Return true if level is larger than amount.
        /// Otherwise remove building and return false.
        /// </summary>
        /// <param name="decreasedLevel"></param>
        /// <returns></returns>
        public bool DecreaseLevel(BuildingType building, uint decreasedLevel = 1)
        {
            if (this.buildingList.ContainsKey(building) == false)
                return false;

            if (this.buildingList[building] > decreasedLevel)
            {
                this.buildingList[building] -= decreasedLevel;
                return true;
            }
            else
            {
                this.Remove(building);
                return false;
            }
        }

        public void SetLevel(BuildingType building, uint level)
        {
            if (this.buildingList.ContainsKey(building))
            {
                this.buildingList[building] = level;
            }
            else
                this.buildingList.Add(building, level);
        }

        #endregion

        #region keys and values

        public ICollection<BuildingType> Keys
        {
            get { return this.buildingList.Keys; }
        }

        public ICollection<uint> Values
        {
            get { return this.buildingList.Values; }
        }

        #endregion

        #region add

        /// <summary>
        /// If key not present add it into dictionary,
        /// else increase its value by value.
        /// </summary>
        /// <param name="key"></param>
        /// <param name="value"></param>
        private void Add(BuildingType key, uint value)
        {
            if (this.buildingList.ContainsKey(key) == false)
            {
                this.buildingList.Add(key, 0); //
            }
            this.IncreaseLevel(key, value);
        }

        #endregion

        #region contains

        public bool ContainsKey(BuildingType key)
        {
            return this.buildingList.ContainsKey(key);
        }

        #endregion

        #region remove

        private bool Remove(BuildingType key)
        {
            if (this.buildingList.ContainsKey(key) == true) // have building
            {
                if (this[key] > 0) // level more than zero
                {
                    if (key != SettlementHelper.Road) // road is special
                    {
                        this.DecreaseLevel(key, this.buildingList[key]); // reduce
                        if (this[key] <= 0) // level is zero 
                            this.buildingList.Remove(key);
                    }
                    else
                        if (this[key] > 1) // road level higher than 1
                            this.DecreaseLevel(key);
                        else
                            // cannot remove
                            // because road always exists and have minial level 1
                            return false;
                    return true;
                }
                else
                {
                    // already not exist
                    this.buildingList.Remove(key);
                    return false;
                }
            }
            else
                return false;
        }

        /// <summary>
        /// Remove all buildings have type flag.
        /// Used when settlement change its type -- city to village or village to city
        /// </summary>
        /// <param name="type"></param>
        public void Remove(SettlementFlags type)
        {
            foreach (var buildingType in new List<BuildingType>(this.buildingList.Keys))
            {
                if (buildingType.Availability.HasFlag(type) == false)
                    this.Remove(buildingType);
            }
        }

        #endregion

        #region clear

        /// <summary>
        /// Remove everything except 1 level road.
        /// </summary>
        public void Clear()
        {
            this.buildingList.Clear();
            this.buildingList.Add(SettlementHelper.Road, 1);
        }

        #endregion

        #region count

        public int Count
        {
            get { return this.buildingList.Count; }
        }

        #endregion
    }
}
